package com.sumainfor.wx.system.config;

import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.sumainfor.common.config.GenerateUUID;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author Eddy·Chen
 * @Email 835033913@qq.com
 * @Create 2019-06-14 16:47
 */
@Configuration
@MapperScan(basePackages = {"com.sumainfor.wx.system.epc.dao", "com.sumainfor.wx.system.gmio.dao", "com.sumainfor.wx.system.maket.dao"},
        sqlSessionTemplateRef = "sqlSessionTemplate", basePackageClasses = {GenerateUUID.class})
public class DataSourceFactory {

    private static final String MAPPER_LOCATION = "classpath:mapper/**/*.xml";

    /**
     * 配置EPC数据源
     *
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource.druid.epc")
    public DataSource druidDataSourceEpc() {
        return new DruidXADataSource();
    }

    /**
     * 配置Gmio数据源
     *
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource.druid.gmio")
    public DataSource druidDataSourceGmio() {
        return new DruidXADataSource();
    }

    /**
     * 配置Market数据源
     *
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource.druid.market")
    public DataSource druidDataSourceMarket() {
        return new DruidXADataSource();
    }

    /**
     * 配置Tenant数据源
     *
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource.druid.tenant")
    public DataSource druidDataSourceTenant() {
        return new DruidXADataSource();
    }

    /**
     * 创建支持XA事务的Atomikos数据源 Epc
     */
    @Bean
    public DataSource dataSourceEpc(DataSource druidDataSourceEpc) {
        AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
        sourceBean.setXaDataSource((DruidXADataSource) druidDataSourceEpc);
        // 必须为数据源指定唯一标识
        sourceBean.setUniqueResourceName("epc");
        return sourceBean;
    }

    /**
     * 创建支持XA事务的Atomikos数据源 Gmio
     */
    @Bean
    public DataSource dataSourceGmio(DataSource druidDataSourceGmio) {
        AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
        sourceBean.setXaDataSource((DruidXADataSource) druidDataSourceGmio);
        // 必须为数据源指定唯一标识
        sourceBean.setUniqueResourceName("gmio");
        return sourceBean;
    }


    /**
     * 创建支持XA事务的Atomikos数据源 Market
     */
    @Bean
    public DataSource dataSourceMarket(DataSource druidDataSourceMarket) {
        AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
        sourceBean.setXaDataSource((DruidXADataSource) druidDataSourceMarket);
        // 必须为数据源指定唯一标识
        sourceBean.setUniqueResourceName("market");
        return sourceBean;
    }


    /**
     * 创建支持XA事务的Atomikos数据源 Tenant
     */
    @Bean
    public DataSource dataSourceTenant(DataSource druidDataSourceTenant) {
        AtomikosDataSourceBean sourceBean = new AtomikosDataSourceBean();
        sourceBean.setXaDataSource((DruidXADataSource) druidDataSourceTenant);
        // 必须为数据源指定唯一标识
        sourceBean.setUniqueResourceName("tenant");
        return sourceBean;
    }

    /**
     * @param dataSourceEpc 数据源 Epc
     * @return 数据源Epc的会话工厂
     */
    @Bean
    public SqlSessionFactory sqlSessionFactoryEpc(DataSource dataSourceEpc)
            throws Exception {
        return createSqlSessionFactory(dataSourceEpc);
    }


    /**
     * @param dataSourceGmio 数据源 Gmio
     * @return 数据源Gmio的会话工厂
     */
    @Bean
    public SqlSessionFactory sqlSessionFactoryGmio(DataSource dataSourceGmio)
            throws Exception {
        return createSqlSessionFactory(dataSourceGmio);
    }


    /**
     * @param dataSourceMarket 数据源 Market
     * @return 数据源Market的会话工厂
     */
    @Bean
    public SqlSessionFactory sqlSessionFactoryMarket(DataSource dataSourceMarket)
            throws Exception {
        return createSqlSessionFactory(dataSourceMarket);
    }

    /**
     * @param dataSourceTenant 数据源 Tenant
     * @return 数据源Tenant的会话工厂
     */
    @Bean
    public SqlSessionFactory sqlSessionFactoryTenant(DataSource dataSourceTenant)
            throws Exception {
        return createSqlSessionFactory(dataSourceTenant);
    }


    /**
     * sqlSessionTemplate与Spring事务管理一起使用，以确保使用的实际SqlSession是与当前Spring事务关联的,
     * 此外它还管理会话生命周期，包括根据Spring事务配置根据需要关闭，提交或回滚会话
     *
     * @param sqlSessionFactoryEpc
     * @param sqlSessionFactoryGmio
     * @param sqlSessionFactoryMarket
     * @param sqlSessionFactoryTenant
     * @return
     */
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactoryEpc,
                                                 SqlSessionFactory sqlSessionFactoryGmio,
                                                 SqlSessionFactory sqlSessionFactoryMarket,
                                                 SqlSessionFactory sqlSessionFactoryTenant) {
        Map<Object, SqlSessionFactory> sqlSessionFactoryMap = new HashMap<>(4);
        sqlSessionFactoryMap.put(DataSourceConst.DATA_EPC, sqlSessionFactoryEpc);
        sqlSessionFactoryMap.put(DataSourceConst.DATA_GMIO, sqlSessionFactoryGmio);
        sqlSessionFactoryMap.put(DataSourceConst.DATA_MARKET, sqlSessionFactoryMarket);
        sqlSessionFactoryMap.put(DataSourceConst.DATA_TENANT, sqlSessionFactoryTenant);

        CustomSqlSessionTemplate customSqlSessionTemplate = new CustomSqlSessionTemplate(sqlSessionFactoryMarket);
        customSqlSessionTemplate.setTargetSqlSessionFactories(sqlSessionFactoryMap);
        return customSqlSessionTemplate;
    }


    /***
     * 自定义会话工厂
     * @param dataSource 数据源
     * @return :自定义的会话工厂
     */
    private SqlSessionFactory createSqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));
        PaginationInterceptor interceptor = new PaginationInterceptor();
        factoryBean.setPlugins(new Interceptor[]{interceptor});
        // 其他可配置项(包括是否打印sql,是否开启驼峰命名等)
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setLogImpl(StdOutImpl.class);
        factoryBean.setConfiguration(configuration);
        return factoryBean.getObject();
    }
}
